'''
    Concrete DocSearcher class.
'''
import os, string, time, PyLucene
from common import EDocIndexer, Hit, decode_input, safe_print
from abstract_indexer import AbstractIndexer


class DocSearcher(AbstractIndexer):

    def __init__(self, searchdir):
        AbstractIndexer.__init__(self)
        self.format = '%(fspath)s'
        self.searcher = None
        self.query = None       # Lucene query Object.
        self.hits = None
        self.searchdir = os.path.abspath(searchdir)
        if not os.path.isdir(self.searchdir):
            raise EDocIndexer,'documents directory not found: %s' % self.searchdir
        # Search up the directory tree for the index directory starting in
        # searchdir.'''
        parent = self.searchdir
        while not os.path.isdir(self.indexdir(parent)):
            (parent,base) = os.path.split(os.path.normpath(parent))
            if base == '':
                raise EDocIndexer,'documents index not found'
        self.docsdir = parent
        self.check_index_exists()
        try:
            store = PyLucene.FSDirectory.getDirectory(self.indexdir(), False)
            self.searcher = PyLucene.IndexSearcher(store)
        except Exception,e:
            raise EDocIndexer,'unable to open documents index: %s' % e

    def parse_query(self, query, and_operator=False):
        ''' Parse query string to Lucene query object.
            If and_operator is True then AND is default conjunction operator.
        '''
        assert isinstance(query, unicode)
        try:
            self.query = PyLucene.QueryParser('content', self.analyzer)
            if and_operator:
                self.query.setDefaultOperator(PyLucene.QueryParser.Operator.AND)
            self.query = self.query.parse(query)
        except:
            raise EDocIndexer,'invalid query: %s' % query
        if self.docsdir != self.searchdir:
            # Add pathname prefix filter.
            prefix = self.indexpath(self.searchdir)
            pfilter = PyLucene.PrefixFilter(PyLucene.Term('pathname', prefix))
            self.query = PyLucene.FilteredQuery(self.query, pfilter)

    def hits_gen(self):
        ''' Returns iterator of hits for the current query.'''
        try:
            self.hits = self.searcher.search(self.query)
        except Exception,e:
            raise EDocIndexer,'search error: %s' % e
        for i, doc in self.hits:
            hit = Hit(self.hits, i)
            hit['fspath'] = self.fspath(hit['pathname'])
            # Don't include files that no longer exist.
            if os.path.isfile(hit['fspath']):
                yield hit

    def printf(self, list=False, summary=False):
        ''' List search results and/or summary.
        '''
        start_time = time.time()
        n = 0
        size = 0
        for hit in self.hits_gen():
            if list:
                safe_print(hit.printf(self.format))
            n += 1
            size += hit['size']
        if summary:
            if list:
                print
            print 'files found:',n
            safe_print('query: %s' % self.query.toString())
            print 'bytes: %0.2fMB' % (size / (1024.0*1024.0))
            print 'elapsed time: %0.2f seconds' % (time.time() - start_time)
        return


# vim: set ts=4 sw=4:
